Fork me on GitHub

Are you OK ? OK了解下

简介

先简单介绍下Okhttp的用法吧:
直接从官网摘的:

1
2
3
4
5
6
7
8
9
10
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}

这是同步的方式,异步就不放了。可以看到里面其实很关键的几个变量或者方法:OkHttpClient、Request、Response、newCall(),newCall其实返回的是一个Call对象,所以OK实际上也就是由这几个关键类构造起来的,为外部提供接口调用。
其他一些OK的详细用法,就不在这里讲了,这篇主要串一下OK的工作原理。

Loading…….


入口

先看下OkhttpClient这个类,它实现了Call.Factory接口,是构建call对象的关键。

1
2
3
4
5
6
7
8
9
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
public OkHttpClient() {
this(new Builder());
}
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
}

Builder是OkHttpClient中的静态内部类,主要是对一些参数进行初始化,比如说dispatcher等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//OkHttpClient.Builder
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;//协议
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}

OkhttpClient中的newCall方法返回了一个realCall对象。我们这里先从同步的方式入手:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
final class RealCall implements Call {
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
@Override
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
}

再看其调用的excute()方法,先同步保证当前call对象只能被执行一次。然后调用dispatcher().executed(this),做一些准备工作。
调用getResponseWithInterceptorChain();来实际执行请求并且获取实际Http返回结果,最后调用dispatcher()通知请求结束。

1
2
3
4
//Dispatcher
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}

runningSyncCalls是一个双向队列,存储的是正在执行的同步的RealCall对象。

核心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//RealCall
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}

Interceptor 这个东西不仅仅是仅仅起了拦截请求的功能,它是OK的核心,把实际的网络请求、IO、缓存、透明压缩等功能都统一了起来,每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终圆满完成一次网络请求。
此处输入图片的描述
可以看到上面代码,责任链的顺序:

  1. 在配置OkhttpClient时设置的interceptor(自定义的interceptor);
  2. 负责失败重试和重定向的拦截器;
  3. 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的网络响应转换为用户响应的 BridgeInterceptor;
  4. 负责请求的缓存,包括读取和写入;
  5. 负责和服务器建立连接的 ConnectInterceptor;
  6. 配置OkHttpClient时设置的 networkInterceptors;
  7. 负责向服务器发送请求数据、从服务器读取响应数据的 CallServerInterceptor。

简单分析下:
1)这里功能虽然复杂,但是最后一个功能一定是负责和服务器进行实际通讯的,关于缓存、重定向之类都是需要在之前设置的。
2)Request通过这个责任链转换为Response, 而每个interceptor都可以独立的返回一个response,交由上层处理。
3)上层链的proceed方法 调用下层的intercept方法执行处理逻辑并继续去调用下层链的proceed,并返回response。层层嵌套,从而执行完整个责任链。这里逻辑的总控在类 RealInterceptorChain 中,大家可以下去仔细看下。
4)这种责任链模式将实际的网络请求操作逻辑给隔离,脱离RealCall,简化了各个部分负责的功能,优雅的实现了最终的需求。

其实这个责任链特别像计网中的分层,有木有! 下层向上层传递数据。

Interceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public final class ConnectInterceptor implements Interceptor {
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client) {
this.client = client;
}
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
}
}

可以看到,建立连接其实就是根据StreamAllocation创建了一个HttpCodec对象和RealConnection对象,httpcodec主要是对http请求进行编码和对响应进行解码,HttpCodec的两个实现类Http2Codec、Http1Codec,很明显是针对Http/1.1 和Http/2版本。
StreamAllocation主要是用来协调Connections、Streams、Calls三个实体类之间的关系。大致上的逻辑就是寻找合适的realconnection,利用 RealConnection 的输入输出(BufferedSource 和 BufferedSink)创建 HttpCodec对象。
比如这样:(只截取了一小段)

1
2
3
RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
writeTimeout, pingIntervalMillis, connectionRetryEnabled, doExtensiveHealthChecks);
HttpCodec resultCodec = resultConnection.newCodec(client, chain, this);

再看看CallServerInterceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public final class CallServerInterceptor implements Interceptor {
private final boolean forWebSocket;
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
HttpCodec httpCodec = realChain.httpStream();
StreamAllocation streamAllocation = realChain.streamAllocation();
RealConnection connection = (RealConnection) realChain.connection();
Request request = realChain.request();
httpCodec.writeRequestHeaders(request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
CountingSink requestBodyOut =
new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
httpCodec.finishRequest();
if (responseBuilder == null) {
responseBuilder = httpCodec.readResponseHeaders(false);
}
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
if (forWebSocket && code == 101) {
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
return response;
}
}

这里只挑出了核心代码,省略了一些监听回调和检查代码。
可以看到它的大致流程:

  1. 通过httpcodec写入request header
  2. 如果request body不为空,则发送到服务器
  3. 读取responseHeader,构建Response
  4. 如果response body不为空,则加入response中
    这4步的核心都是由HttpCodec完成,HttpCodec的底层又是通过Okio,而Okio实际上还是用的Socket(socket逻辑实现在RealConnection中)。这里具体的逻辑就不分析了,有兴趣的童鞋可以去了解下。

经过上面的同步请求execute后,我们就能拿到返回的Response。
注意:响应的其他部分可以随意获取,但是response.body必须通过数据流的方式来进行访问(ok也提供了 body.string() 和 bytes() 这样的方法将流内的数据一次性读取完毕)。响应的 body 被封装到 ResponseBody 类中,该类主要有两点需要注意:
(1)每个 body 只能被消费一次,多次消费会抛出异常;
(2)body 必须被关闭,否则会发生资源泄漏;


异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//RealCall
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
//Dispatcher
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost){
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
public synchronized ExecutorService executorService() {
if (executorService == null) {
//核心线程数为0,当线程空闲时只能活60秒,不存储元素的阻塞工作队列
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}

可以看到异步enqueue()方法主要是通过dispatcher来执行,如果队列runningAsyncCalls当前还能执行一个并发请求(具体的判断标准:即正在执行的异步队列中Call对象个数小于maxRequests(64)并且执行队列中的同一个host对应的Call对象个数小于maxRequestsPerHost(5)的时候),则调用executorService立即执行,可以看到这个executorService就是一个可缓存线程池。否则 将任务加入队列readyAsyncCalls,等待正在执行的Call请求的完成,调用promoteCalls,将call请求加入running状态中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() { return originalRequest.url().host(); }
Request request() { return originalRequest; }
RealCall get() { return RealCall.this; }
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}

上面的AsyncCall 是RealCall中的一个内部类,它实现了Runnable接口,所以可以直接提交给线程池执行,这里的run方法在父类NamedRunnable 中,内部其实调用的还是子类的execute方法,因此这里获取response的逻辑还是通过getResponseWithInterceptorChain责任链来进行的,最后通过接口回调responseCallback将响应发回去。注意这里是没有做线程切换的,所以想要UI更新的童鞋注意了。

Last

本篇只是简单的介绍了ok的工作流程,里面详细的工作机制,比如socket连接池、缓存策略等,只能期待下一篇了。